package com.ai.trickycards.utils

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.animation.BounceInterpolator
import android.view.animation.Interpolator
import android.view.animation.LinearInterpolator
import androidx.core.animation.doOnEnd
import com.ai.trickycards.widgets.PokerCardComposeView
import com.ai.trickycards.widgets.PokerCardView
import kotlin.math.abs

object PokerUtils {

    private var _showFace = false
    private lateinit var moveParam: List<List<Float>>

    /**
     * 重新叠放扑克牌
     * @param pokerCardCompose
     * @param centerTop 中间张扑克在最顶上
     */
    fun reLayer(
        pokerCardCompose: PokerCardComposeView,
        centerTop: Boolean
    ) {
        pokerCardCompose.pokerCardViews.takeLast(2).forEachIndexed { index: Int, pokerCardView: PokerCardView ->
            if (centerTop) {
                pokerCardView.translationZ = -(index + 1) * 10f
            } else {
                pokerCardView.translationZ = 0f
            }
        }
    }

    /**
     * 翻转人类的牌
     * @param showFace 是否显示正面
     */
    fun flipPoker(
        pokerCardComposeFace: PokerCardComposeView,
        pokerCardComposeBack: PokerCardComposeView,
        showFace: Boolean
    ) {
        if (_showFace != showFace && ::moveParam.isInitialized) {
            _showFace = showFace
            val targetProcess = if (showFace) 1f else 0f
            rub(pokerCardComposeFace, true, moveParam, targetProcess)
            rub(pokerCardComposeBack, false, moveParam, targetProcess)
        }
    }


    /**
     * 人类搓牌
     */
    @SuppressLint("ClickableViewAccessibility")
    fun rub(
        context: Context,
        pokerCardComposeFace: PokerCardComposeView,
        pokerCardComposeBack: PokerCardComposeView
    ) {
        var downY = 0f
        var startMove = false
        val density = context.resources.displayMetrics.density
        moveParam = listOf(
            // translationX,fromTranslationY, toTranslationY, fromRotation, toRotation
            listOf(96 * density, pokerCardComposeBack.pokerCardViews[0].translationY, -6 * density, -10f, 0f),
            listOf(114 * density, pokerCardComposeBack.pokerCardViews[1].translationY, -3 * density, -5f, 5f),
            listOf(132 * density, pokerCardComposeBack.pokerCardViews[2].translationY, 6 * density, 0f, 10f),
            listOf(-130 * density, pokerCardComposeBack.pokerCardViews[3].translationY, -2 * density, 5f, -5f),
            listOf(-240 * density, pokerCardComposeBack.pokerCardViews[4].translationY, 6 * density, 10f, -10f)
        )

        val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent): Boolean {
                _showFace = !_showFace
                execFloatAnim(
                    from = if (_showFace) 0f else 1f,
                    to = if (_showFace) 1f else 0f,
                    animDuration = if (_showFace) 500 else 200,
                    animInterpolator = if (_showFace) BounceInterpolator() else LinearInterpolator(),
                    updateListener = {
                        val animValue = it.animatedValue as Float
                        rub(pokerCardComposeFace, true, moveParam, animValue)
                        rub(pokerCardComposeBack, false, moveParam, animValue)
                    })
                return false
            }
        })

        pokerCardComposeBack.setOnTouchListener { v, event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    downY = event.y
                }

                MotionEvent.ACTION_MOVE -> {
                    if (!_showFace) {
                        val delta = downY - event.y
                        if (startMove || delta > 0) {
                            startMove = true
                            val process = (delta / v.height * 2f).coerceIn(0f, 1f)
                            rub(pokerCardComposeFace, true, moveParam, process)
                            rub(pokerCardComposeBack, false, moveParam, process)
                        }
                    }

                }

                MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                    if (startMove && !_showFace) {
                        val delta = downY - event.y
                        startMove = false
                        val process = (delta / v.height * 2f).coerceIn(0f, 1f)
                        val startProcess = if (process > 0.5f) 0.5f else process
                        val targetProcess = if (process > 0.5f) 1f else 0f
                        _showFace = targetProcess == 1f
                        val duration = (800 * abs(targetProcess - startProcess)).toLong()
                        execFloatAnim(
                            from = startProcess,
                            to = targetProcess,
                            animDuration = duration,
                            animInterpolator = BounceInterpolator(),
                            updateListener = {
                                val animValue = it.animatedValue as Float
                                rub(pokerCardComposeFace, true, moveParam, animValue)
                                rub(pokerCardComposeBack, false, moveParam, animValue)
                            })
                    }
                }
            }
            gestureDetector.onTouchEvent(event)
            true
        }
    }

    private fun execFloatAnim(
        from: Float,
        to: Float,
        animDuration: Long = 500,
        animInterpolator: Interpolator = LinearInterpolator(),
        updateListener: ((ValueAnimator) -> Unit)? = null,
        endListener: (() -> Unit)? = null,
    ) {
        ValueAnimator.ofFloat(from, to).apply {
            setDuration(animDuration)
            interpolator = animInterpolator
            addUpdateListener { updateListener?.invoke(it) }
            doOnEnd { endListener?.invoke() }
            start()
        }
    }

    private fun rub(
        pokerCardCompose: PokerCardComposeView,
        show: Boolean,
        moveParam: List<List<Float>>,
        process: Float
    ) {
        pokerCardCompose.pokerCardViews.forEachIndexed { index, pokerCardView ->
            pokerCardView.alpha = if (show) process else 1 - process
            println("moveParam=$index, $moveParam[index]")
            doRub(
                v = pokerCardView,
                toTranslationX = moveParam[index][0],
                fromTranslationY = moveParam[index][1],
                toTranslationY = moveParam[index][2],
                fromRotation = moveParam[index][3],
                toRotation = moveParam[index][4],
                process = process
            )
        }
    }

    private fun doRub(
        v: View,
        toTranslationX: Float,
        fromTranslationY: Float,
        toTranslationY: Float,
        fromRotation: Float,
        toRotation: Float,
        process: Float
    ) {
        v.translationX = toTranslationX * process
        v.translationY = fromTranslationY + (toTranslationY - fromTranslationY) * process
        v.rotation = fromRotation + (toRotation - fromRotation) * process
        v.scaleX = 1 + 0.25f * process
        v.scaleY = 1 + 0.25f * process
    }

}